package com.yami.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.EsOperationType;
import com.yami.shop.bean.enums.ProdStatusEnums;
import com.yami.shop.bean.event.CategoryWordEvent;
import com.yami.shop.bean.event.EsProductUpdateEvent;
import com.yami.shop.bean.model.Blockchain;
import com.yami.shop.bean.model.BlockchainShop;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.vo.BlockchainInfoVo;
import com.yami.shop.bean.vo.BlockchainVo;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.CacheManagerUtil;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.SpringContextUtils;
import com.yami.shop.dao.BlockchainMapper;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.service.BlockchainService;
import com.yami.shop.service.BlockchainShopService;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author LGH
 */
@Service
@AllArgsConstructor
public class BlockchainServiceImpl extends ServiceImpl<BlockchainMapper, Blockchain> implements BlockchainService {

    private final BlockchainMapper blockchainMapper;
    private final BlockchainShopService blockchainShopService;
    private final ProductMapper productMapper;
    private final ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBlockchain(Blockchain blockchain) {
        blockchain.setCreateTime(new Date());
        // 保存分类信息
        save(blockchain);
        // 删除缓存信息
        CacheManagerUtil cacheManagerUtil = SpringContextUtils.getBean(CacheManagerUtil.class);
        cacheManagerUtil.evictCache("SysConfigObject", Constant.SOURCE_CHAIN_CODE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBlockchain(Blockchain blockchain) {
        Blockchain blockchainDb = blockchainMapper.selectById(blockchain.getId());
        blockchain.setUpdateTime(new Date());
        // 保存分类信息
        blockchainMapper.updateById(blockchain);
        if (Objects.equals(blockchainDb.getStatus(), 0)) {
            // 从正常改为下线
            // 批量修改已经下架的分类下的商品的状态
            List<String> chainCodes = new ArrayList<>();
            chainCodes.add(blockchainDb.getCode());
            productMapper.offlineProdByChainCodesId(chainCodes, ProdStatusEnums.SHOP_OFFLINE.getValue());
            List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>().in(Product::getChain, chainCodes));
            // 删除所有店铺的分类缓存
            List<Long> shopIdList = products.stream().map(Product::getShopId).collect(Collectors.toList());
            blockchainShopService.removeCacheByShopIds(shopIdList);
            List<Long> prodIds = products.stream().map(Product::getProdId).collect(Collectors.toList());
            // 更新es中的商品
            eventPublisher.publishEvent(new EsProductUpdateEvent(null, prodIds, EsOperationType.UPDATE_BATCH));
            // 失效包括该分类商品的活动
            eventPublisher.publishEvent(new CategoryWordEvent(prodIds));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBlockchain(Blockchain blockchain) {
        blockchainMapper.deleteById(blockchain.getId());
        // 如果删除需要删除店铺链平台关联关系表中该链平台的数据
        blockchainShopService.deleteByBlockchainId(blockchain.getId());
    }

    @Override
    public Blockchain getBlockchainByBlockchainId(Long blockchainId) {
        Blockchain blockchain = blockchainMapper.getBlockchain(blockchainId);
        if (blockchain == null) {
            // 无法获取链平台信息
            throw new YamiShopBindException("yami.unable.get.classification");
        }
        return blockchain;
    }

    @Override
    public Integer getBlockchainName(Blockchain blockchain) {
        return blockchainMapper.getBlockchainName(blockchain);
    }


    @Override
    public IPage<Blockchain> pageCategoryLangList(PageParam<Blockchain> page, Blockchain blockchain) {
        IPage<Blockchain> categoryIPage = blockchainMapper.blockchainLangList(page, blockchain);
        return categoryIPage;
    }

    @Override
    public List<Long> updateBlockchainStatus(Blockchain blockchain) {
        Blockchain dbBlockchain = blockchainMapper.selectById(blockchain.getId());
        if (Objects.isNull(dbBlockchain) || dbBlockchain.getStatus().equals(dbBlockchain.getStatus())) {
            return null;
        }
        blockchainMapper.updateBlockchainStatus(blockchain);
        List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>().eq(Product::getChain, dbBlockchain.getCode()));
        List<Long> prodIds = products.stream().map(Product::getProdId).collect(Collectors.toList());
        // 查询出秒杀or团购的商品进行下线
        eventPublisher.publishEvent(new EsProductUpdateEvent(null, prodIds, EsOperationType.UPDATE_BATCH));
        return prodIds;
    }

    @Override
    public List<Blockchain> listByParams(Blockchain blockchain) {
        return blockchainMapper.listByParams(blockchain);
    }

    @Override
    public Blockchain getInfoByCode(String code) {
        return blockchainMapper.getInfoByCode(code);
    }

    @Override
    public List<BlockchainInfoVo> listbyshopId(Long shopId) {
        LambdaQueryWrapper<BlockchainShop> eq = new LambdaQueryWrapper<BlockchainShop>().eq(BlockchainShop::getShopId, shopId).eq(BlockchainShop::getIsCoin, 1);
        List<BlockchainShop> list = blockchainShopService.list(eq);
        List<BlockchainInfoVo> blockchainVoList = new ArrayList<>();
        for(BlockchainShop blockchainShop : list){
            BlockchainInfoVo blockchainInfoVo = new BlockchainInfoVo();
            blockchainInfoVo.setCode(blockchainShop.getBlockchainCode());
            LambdaQueryWrapper<Blockchain> blockchainLambdaQueryWrapper = new LambdaQueryWrapper<Blockchain>().eq(Blockchain::getCode, blockchainShop.getBlockchainCode());
            Blockchain one = this.getOne(blockchainLambdaQueryWrapper);
            blockchainInfoVo.setName(one.getName());
            blockchainVoList.add(blockchainInfoVo);
        }
        return blockchainVoList;
    }

}
